namespace BM.Tools.WebControls.MForm.Generator
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Web.UI;
    using System.Xml;
    using System.Xml.Schema;

    using BM.Tools.WebControls.MForm.Generator.Templates;
    using BM.Tools.Xml.Schema;

    /// <summary>
    /// The form builder class is an implementation of the <see cref="Visitor{TVisited}" /> class
    /// that goes through the xml schema definitions and collects <see cref="FormVisited" /> objects and references between them
    /// </summary>
    public class FormBuilder : Visitor<FormVisited>
    {                        
        private FormBuilderSettings settings = new FormBuilderSettings();               

        /// <summary>
        /// Initializes a new instance of the <see cref="FormBuilder"/> class. 
        /// </summary>
        /// <param name="xs">
        /// The xml schema set.
        /// </param>
        public FormBuilder(XmlSchemaSet xs) : base(xs, new FormVisitedFactory())
        {
        }

        /// <summary>
        /// Gets Settings.
        /// </summary>
        public FormBuilderSettings Settings
        {
            get
            {
                return settings;
            }

            internal set
            {
                settings = value;
            }
        }

        /*// <summary>
        /// Traverses a xml schema element
        /// </summary>
        /// <param name="xse">
        /// The xml schema element.
        /// </param>
        /// <returns>
        /// the Visited object
        /// </returns>
        public override FormVisited TraverseElement(XmlSchemaElement xse)
        {
            rootElement = (FormItem)CreateCurrent(null, xse);
            TraverseElement(xse, rootElement);            
            return rootElement;
        }*/

        /// <summary>
        /// Traverses base type
        /// </summary>
        /// <param name="typeCode">
        /// The base type code
        /// </param>
        /// <param name="formVisited">
        /// The visited object.
        /// </param>
        protected override void TraverseBaseType(XmlTypeCode typeCode, FormVisited formVisited)
        {            
            var formItem = formVisited.FormItem;
            formItem.DataType = typeCode;
            if (formItem.DataType.Equals(XmlTypeCode.Date))
            {
                formItem.MaxLength = 11;
            }

            formItem.IsLeaf = true;
        }

        /// <summary>        
        /// Traverses complex content restriction
        /// Becuase complex content restriction repeats all the data specified in its base type, the base type name is not traversed.
        /// </summary>
        /// <param name="xsccr">
        /// The xml schema complex content restriction.
        /// </param>
        /// <param name="v">
        /// The visited object.
        /// </param>
        protected override void TraverseComplexContentRestriction(XmlSchemaComplexContentRestriction xsccr, FormVisited v)
        {
            TraverseAttributes(xsccr.Attributes, v);
            TraverseAnnotated(xsccr.Particle, v);
        }

        /// <summary>
        /// Traverses schema enumeration facet
        /// </summary>
        /// <param name="schemaEnumerationFacet">
        /// The schema enumeration facet.
        /// </param>
        /// <param name="formVisited">
        /// The visited object.
        /// </param>
        protected override void TraverseEnumerationFacet(XmlSchemaEnumerationFacet schemaEnumerationFacet, FormVisited formVisited)
        {        
            var formItem = formVisited.FormItem;
            formItem.Options.Add(schemaEnumerationFacet.Value);
        }

        /// <summary>
        /// Traverses facet
        /// </summary>
        /// <param name="schemaFacet">
        /// The xml schema facet.
        /// </param>
        /// <param name="formVisited">
        /// The visited object.
        /// </param>
        protected override void TraverseFacet(XmlSchemaFacet schemaFacet, FormVisited formVisited)
        {
            var enumerationFacet = schemaFacet as XmlSchemaEnumerationFacet;
            if (enumerationFacet != null)
            {
                TraverseEnumerationFacet(enumerationFacet, formVisited);
                return;
            }

            var formItem = formVisited.FormItem;
            string typename = schemaFacet.GetType().Name;
            string type = typename.Substring(9, typename.Length - 14);            
            formItem.AddRestriction(type, schemaFacet.Value);
            if (schemaFacet is XmlSchemaMaxLengthFacet || schemaFacet is XmlSchemaLengthFacet)
            {
                formItem.MaxLength = Convert.ToInt32(schemaFacet.Value, CultureInfo.InvariantCulture);
            }
        }

        /// <summary>
        /// Traverses schema identity constraint
        /// </summary>
        /// <param name="schemaIdentityConstraint">
        /// The xml schema identity constraint
        /// </param>
        /// <param name="formVisited">
        /// The visited object.
        /// </param>
        protected override void TraverseIdentityConstraint(XmlSchemaIdentityConstraint schemaIdentityConstraint, FormVisited formVisited)
        {        
            var formItem = formVisited.FormItem;
            formItem.IdentityConstraints.Add(schemaIdentityConstraint);
        }
    }
}